﻿using Autofac.Core;
using LiveCharts;
using LiveCharts.Defaults;
using LiveCharts.Wpf;
using MaterialDesignThemes.Wpf;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Windows.Interop;
using System.Windows.Media;
using VIA.Foundation;
using VIA.Integration;
using VIA.Integration.Domain;
using VIA.Integration.Domain.Production;
using VIA.Presentation;
using VIA.Presentation.Contracts;
using VIA.Presentation.Services;
using VIA.Project.Domain.Services;
using VIA.RbacPassport;
using VIA.RbacPassport.Presentation;
using VIA.SiMoJi.Domain;
using VIA.SiMoJi.Domain.Electronics;
using VIA.SiMoJi.Domain.Inspection;
using VIA.SiMoJi.Presentation;
using VIA.Toolkit;

namespace VIA.Project.Presentation.ViewModel.Inspection
{

    [ViewModel(typeof(IHomePanelView), IsShared = true)]
    internal class HomePanelViewModel : ViewModel<IHomePanelView>
    {
        #region Fields

        readonly IMessageService _messageService;
        readonly IApplicationLog _applicationLog;
        IShellService _shellService;
        private Shift _currentShift;
        private ObservableValue _okValue = new ObservableValue(0);
        private ObservableValue _ngValue = new ObservableValue(0);
        private Inspector _inspector;
        private readonly ILogger _logger;
        private readonly IBusyService _busyService;
        public LoginOption _loginOption;
        private readonly ICommandFactory _commandFactory;
        private IDispatcherService _dispatcher;
        private IOptionRepository _optionRepository;
        private VisionStation _station;
        private CancellationTokenSource _refreshCts;
        readonly ILoginService _loginService;
        readonly IZKTEcoFace _zktecoFace;
        readonly ICurrentUser _currentUser;
        EquipmentRunState _eqpRunState;
        EquipmentManualAutoState _eqpAutoState;
        #endregion

        public Shift CurrentShift
        {
            get => _currentShift;
            set => SetProperty(ref _currentShift, value);
        }

        public SeriesCollection YieldSeries { get; private set; }

        public double Yield
        {
            get
            {
                var total = _ngValue.Value + _okValue.Value;
                if (total == 0)
                    return 0;
                return _okValue.Value / total;
            }
        }
        public EquipmentRunState EqpRunState
        {
            get => _eqpRunState;
            set => SetProperty(ref _eqpRunState, value);
        }
        public EquipmentManualAutoState EqpAutoState
        {
            get => _eqpAutoState;
            set => SetProperty(ref _eqpAutoState, value);
        }

        public bool IsDataEnable { get => isDataEnable; set => SetProperty(ref isDataEnable, value); }

        #region Commands

        public IRelayCommand ClearCommand { get; }
        public IRelayCommand RunCommand { get; }
        public IRelayCommand StopCommand { get; }
        public IRelayCommand ClearAlarmCommand { get; }
        public IRelayCommand InitCommand { get; }
        public IRelayCommand LoginCommand { get; }
        public IRelayCommand ClearLogCommand { get; }
        public IRelayCommand OpenLogCommand { get; }
        public IRelayCommand OpenImageCommand { get; }
        public IRelayCommand OpenDataCommand { get; }
        public IRelayCommand RegisterCommand { get; }
        public IRelayCommand TestCommand { get; }
        #endregion

        ~HomePanelViewModel()
        {
            _refreshCts?.Cancel();
        }
        readonly IServiceProvider _service;
        public HomePanelViewModel(IServiceProvider service, ICommandFactory commandFactory, IDispatcherService dispatcherService, IShiftService shiftService, Inspector inspector, IBusyService busyService, IApplicationLog applicationLog, IMessageService messageService, ILogger<HomePanelViewModel> logger, IShellService shellService, IOptionRepository optionRepository)
        {
            _service = service;
            _applicationLog = applicationLog;
            _messageService = messageService;
            _shellService = shellService;
            _logger = logger;
            _inspector = inspector;
            this._commandFactory = commandFactory;
            _dispatcher = dispatcherService;
            _optionRepository = optionRepository;
            _station = inspector.VisionStation;
            ClearCommand = commandFactory.Create(Clear);
            RunCommand = commandFactory.Create(Run, CanRun);
            StopCommand = commandFactory.Create(Stop);
            ClearAlarmCommand = commandFactory.Create(ClearAlarm, () => _inspector.RunState != RunState.Running);
            InitCommand = commandFactory.Create(InitStationAsync, CanInit);
            LoginCommand = commandFactory.Create(Login);
            ClearLogCommand = commandFactory.Create(ClearLog);
            OpenLogCommand = commandFactory.Create(OpenLog);
            OpenImageCommand = commandFactory.Create(OpenImage);
            OpenDataCommand = commandFactory.Create(OpenData);
            _inspector.StatusChanged += Inspector_StatusChanged;
            _inspector.ManualAutoStateChanged += Inspector_ManualAutoStateChanged;
            CurrentShift = shiftService.Current;
            shiftService.ShiftChanged += ShiftService_ShiftChanged;
            _busyService = busyService;
            InitSeries();
            _loginOption = new LoginOption() { Title = "Login" };
            RegisterCommand = _commandFactory.Create(Register);
            _loginService = service.GetService<ILoginService>();
            _zktecoFace = _service.GetService<IZKTEcoFace>();
            _zktecoFace.LoginLoginEvent += ZKTEcoFace_LoginLoginEvent;
            _currentUser = service.GetService<ICurrentUser>();
            _currentUser.UserChanged += CurrentUser_UserChanged;
            TestCommand = _commandFactory.Create(Test);
            Refresh();
        }

        private void CurrentUser_UserChanged(object sender, UserChangedEventArgs e)
        {
            IsDataEnable = _currentUser.IsGranted(PermissionProvider.DataEnable);
        }

        void Test()
        {
            var inspector = _service.GetService<Inspector>();
            _ = inspector.BanYunStation.Step11_放NG料_测试();
        }

        protected override void OnAttach()
        {
            try
            {
                EqpAutoState = Electronic.Default.GetIsAutoRun() ? EquipmentManualAutoState.Auto : EquipmentManualAutoState.Manual;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
            }
        }

        async void ZKTEcoFace_LoginLoginEvent(object? sender, ZKTEcoFaceLoginEvents e)
        {
            string msg = "用户登录成功";
            try
            {

                if (_currentUser.User.Account == e.Request.Account)
                    return;
                await _loginService.LoginAsync(e.Request.Account, e.Request.Account);
                msg = $"{msg}[{_currentUser.User.Name}]";
                _logger.LogInformation(msg);
                _applicationLog.Log(LoggerCategory.RunningInfo, msg);
            }
            catch (Exception ex)
            {
                msg = $"用户登录失败[{e.Request.Account}]{ex.Message}";
                _logger.LogError(ex, msg);
                _applicationLog.LogError(LoggerCategory.RunningInfo, msg);
            }
        }

        private void Inspector_StatusChanged(object? sender, PartStateChangedEventArgs e)
        {
            _dispatcher.Invoke(() =>
            {
                _commandFactory.RaiseCanExecuteChanged();
                switch (e.CurrentState)
                {
                    case RunState.Stop:
                        EqpRunState = EquipmentRunState.Stop;
                        break;
                    case RunState.Running:
                        EqpRunState = EquipmentRunState.Running;
                        break;
                    case RunState.Pause:
                        EqpRunState = EquipmentRunState.Pause;
                        break;
                }
            });
        }

        private void Inspector_ManualAutoStateChanged(object sender, ManualAutoStateChangedEventArgs e)
        {
            _dispatcher.InvokeAsync(() => EqpAutoState = e.State);
        }

        public bool CanRun()
        {
            return _inspector.CanRun(out string msg);
        }
        public bool CanInit()
        {
            return _inspector.CanInit(out string msg);
        }
        private async Task Run()
        {
            try
            {
                using (var scope = _busyService.Begin("设备正在启动中..."))
                {
                    await Task.Run(() => _inspector.Run(RunningMode.Online));
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                _applicationLog.LogError(e.Message);
            }
        }

        private async Task Stop()
        {
            try
            {
                using (_busyService.Begin("设备正在停止..."))
                {
                    await Task.Run(() =>
                    {
                        _inspector.Stop();
                        _applicationLog.Log("设备已停止运行");
                    });
                }
            }
            catch (InspectorStopException e)
            {
                if (await _messageService.ShowYesNoQuestionAsync(_shellService.ShellWindow, "设备流程正在进行中，是否要强制停止?", e.Message))
                {
                    using (_busyService.Begin("设备正在停止..."))
                    {
                        await Task.Run(() =>
                        {
                            _inspector.ForceStop();
                            _applicationLog.Log("设备已停止运行");
                        });
                    }
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
            }
        }

        private async Task ClearAlarm()
        {
            await Task.Run(() =>
            {
                _inspector.Resume();
            });
        }

        private async Task InitStationAsync()
        {
            await Task.Run(async () =>
            {
                EqpRunState = EquipmentRunState.Initialize;
                await _inspector.InitializeStation();
                if (_inspector.IsStationInitialized)
                {
                    EqpRunState = EquipmentRunState.InitializeDone;
                }
                else
                {
                    EqpRunState = EquipmentRunState.Uninitialized;
                }
            });
        }

        private void ShiftService_ShiftChanged(object? sender, ShiftChangedEventArgs e)
        {
            View.Dispatcher.Invoke(() =>
            {
                CurrentShift = e.Current;
            });
        }

        private void OpenImage()
        {
            DataStorageOption DataOption = _optionRepository.Get<DataStorageOption>();
            string dir = Path.Combine(DataOption.ResultImagePath, DateTime.Now.ToString("yyyy-MM-dd"));
            if (Directory.Exists(dir))
            {
                Process.Start("explorer", dir);
            }
            else
            {
                dir = Path.Combine(DataOption.ResultImagePath, DateTime.Now.ToString("yyyy-MM-dd"));
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                Process.Start("explorer", dir);
            }
        }

        private void OpenData()
        {
            DataStorageOption DataOption = _optionRepository.Get<DataStorageOption>();
            string dir = Path.Combine(DataOption.CSVPath);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            Process.Start("explorer", dir);
        }

        void OpenLog()
        {
            var baseDir = AppDomain.CurrentDomain.BaseDirectory;
            var logPath = System.IO.Path.Combine(baseDir, "Logs");
            Process.Start("explorer", logPath);
        }

        void ClearLog()
        {
            _dispatcher.Invoke(() =>
            {
                var log = _applicationLog.Get("app");
                _applicationLog.Get("AlgorithmAlgorithm").Clear();
                _applicationLog.Get("Communication").Clear();
            });
        }

        object _locker = new object();
        private bool isDataEnable;

        void Login()
        {
            RbacPassportHelper.Authorization.LoginCommand?.Execute(_loginOption);
        }

        void Clear()
        {
        }
        public void Refresh()
        {
            _refreshCts?.Cancel();
            _refreshCts = new CancellationTokenSource();
            Task.Factory.StartNew(async () =>
            {
                while (!_refreshCts.IsCancellationRequested)
                {
                    try
                    {
                        await Task.Delay(100);
                        _dispatcher.Invoke(() =>
                        {
                            RunCommand.RaiseCanExecuteChanged();
                            StopCommand.RaiseCanExecuteChanged();
                            InitCommand.RaiseCanExecuteChanged();
                            ClearAlarmCommand.RaiseCanExecuteChanged();
                        });
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex.Message);
                    }
                }
            }, TaskCreationOptions.LongRunning);
        }

        async Task Register()
        {
            var dialogHost = _service.GetService<IDialogHost>();
            var userView = _service.GetService<IUserPermissionEntryView>();
            var dialog = dialogHost.Create(userView);
            await dialog.ShowDialog();
        }
        #region Methods
        void InitSeries()
        {
            YieldSeries = new SeriesCollection()
            {
                  new PieSeries
                {
                    Title = "OK",
                    Values = new ChartValues<ObservableValue> { _okValue },
                    DataLabels = true,
                    Fill =Brushes.LimeGreen,
                    FontSize= 16,
                    Foreground= Brushes.Black
                },
                new PieSeries
                {
                    Title = "NG",
                    Values = new ChartValues<ObservableValue> { _ngValue },
                    DataLabels = true,
                    Fill = Brushes.Crimson,
                    FontSize= 16,
                    Foreground= Brushes.Black
                }
            };

        }

        #endregion
    }

    public enum EquipmentRunState
    {
        /// <summary>
        /// 未初始化
        /// </summary>
        [Description("未初始化")]
        Uninitialized,
        /// <summary>
        /// 初始化中
        /// </summary>
        [Description("初始化中")]
        Initialize,
        /// <summary>
        /// 初始化完成
        /// </summary>
        [Description("初始化完成")]
        InitializeDone,
        /// <summary>
        /// 运行中
        /// </summary>
        [Description("运行中")]
        Running,
        /// <summary>
        /// 停止
        /// </summary>
        [Description("停止中")]
        Stop,
        /// <summary>
        /// 暂停
        /// </summary>
        [Description("暂停中")]
        Pause
    }
}
